package znet

import (
	"errors"
	"fmt"
	"net"
	"zinx/utils"
	"zinx/ziface"
)

/*
  链接模块
*/
type Connection struct {
	// 当前链接的
	Conn *net.TCPConn
	/// 链接id
	ConnID uint32
	/// 当前的链接状态
	isClosed bool
	/// 告知当前链接已经退出的/停止channel
	ExitChan chan bool
	/// 当前链接绑定的router
	Router ziface.IRouter
}

func (connection *Connection) readerData() {
	defer fmt.Println("Conn ", connection.Conn, "reader is exit , remoteAddr is ", connection.Conn.RemoteAddr().String())
	defer connection.Stop()

	for {
		buf := make([]byte, utils.GlobalObject.MaxPackageSize)
		_, err := connection.Conn.Read(buf)
		if err != nil {
			fmt.Println("Conn readerData filed err = ", err)
			continue
		}

		/// 此处应该构建一个request， 传入router， 然后通过router执行相应的方法
		req := Request{
			Conn: connection,
			data: buf,
		}

		go func(req ziface.IRequest) {
			connection.Router.PreHandle(req)
			connection.Router.Handle(req)
			connection.Router.PostHandle(req)
		}(&req)
	}
}
func (connection *Connection) Start() {
	fmt.Println("Conn Start()... ConnID = ", connection.ConnID, "Remote Addr = ", connection.Conn.RemoteAddr())

	/// 循环读取数据
	go connection.readerData()
}

// 停止链接 结束当前的链接工作
func (connection *Connection) Stop() {
	fmt.Println("Conn Stop()... ConnID = ", connection.ConnID)

	/// 链接已经关闭，就不用执行了
	if connection.isClosed == true {
		return
	}

	/// 赋值
	connection.isClosed = true
	/// 链接关闭
	connection.Conn.Close()
	/// 关闭通道
	close(connection.ExitChan)
}

// 获取当前链接的绑定socket conn
func (connection *Connection) GetTCPConnection() *net.TCPConn {
	return connection.Conn
}

// 获取当前链接模块的链接id
func (connection *Connection) GetConnID() uint32 {
	return connection.ConnID
}

/// 获取远程客户端的 tcp 状态 ip port
func (connection *Connection) RemoteAddr() net.Addr {
	return connection.Conn.RemoteAddr()
}

/// 发送数据， 将数据发送给远程客户端
func (connection *Connection) Send(data []byte) error {
	return errors.New("send error")
}

/// 初始化链接模块的方法
func NewConnection(conn *net.TCPConn, connID uint32, router ziface.IRouter) ziface.IConnection {
	c := &Connection{
		Conn:     conn,
		ConnID:   connID,
		isClosed: false,
		ExitChan: make(chan bool, 1),
		Router:   router,
	}

	return c
}
